#pragma once
#include<string>
#include<vector>
#include"KMP.h"
#include"time.h"
#include<cmath>
#include<map>
#include<iterator>
#include<algorithm>
#include<queue>
#include <climits> // For INT_MAX
#include <functional> 
#include <graphics.h>		//图形插件
#include <conio.h>			//getch()头文件
#include <easyx.h>
#include<string>

using namespace std;

class Dot;
class Scenery;
class Line;
class Straight;
class Curve;
class Ray;
class SchoolBus;

__declspec(selectany) vector<Dot*>DotKu;
__declspec(selectany) vector<Line*>LineKu;
__declspec(selectany) map<string, Dot*>SceneryKu;        //用于查询景点信息
__declspec(selectany) map<Dot*, int>DotSearch;           //查询点在库中的下标，以便于最短路径算法的实现
//声明__declspec(selectany)防止重定义链接器错误

__declspec(selectany) int DotID = 1;         //这个值最后也要保存入txt文件中

__declspec(selectany) IMAGE BlackDot, CrossRoadImage, RedDot, OrangeDot, StationImage, GreenDot;    //图片素材

const double eps = 1e-8;             //浮点数比较的精度
const double DotSize = 2;          //单个点作图时的尺寸，可能到时候会根据实际情况调整这个数值
const double ScenerySize = 30;       //景点作图时的尺寸，可能到时候会根据实际情况调整这个数值
const double CrossSize = 15;        //十字路口作图时的尺寸，可能到时候会根据实际情况调整这个数值
const double StationSize = 15;     //公交站点作图时的尺寸，可能到时候会根据实际情况调整这个数值

class Dot {     //点类
private:
	int ID;
	double x;
	double y;  //坐标	
	vector<Ray>Connection;    //图存储结构，存储这个点相连的点
protected:int type;
public:IMAGE* image;     //景点图片(基类指针要有派生类的功能）
	  string name;
	  string portrait;   //对景点的描述，介绍
	  string place;      //景点地点
	  vector<Period>Green1;          //四个路口绿灯时段，以北或者东北为第一象限，逆时针旋转90度分别得2、3、4象限
	  vector<Period>Green2;
	  vector<Period>Green3;
	  vector<Period>Green4;
	  Dot(int a, double b, double c) :ID(a), x(b), y(c), type(0) {
		  if (ID != -1) {
			  DotKu.push_back(this);
			  DotSearch[this] = DotKu.size() - 1;
		  }
		  name = "Error";
		  image = NULL;
	  };
	  virtual int GetID() { return ID; }
	  virtual double Getx() { return x; }
	  virtual double Gety() { return y; }
	  virtual vector<Ray> GetConnection() { return Connection; }
	  virtual int Gettype() { return type; }
	  virtual void AddConnection(Ray* a) {
		  this->Connection.push_back(*a);
	  }
	  friend class Line;
	  friend class Straight;
	  virtual string Getname() = 0; //抽象类，设置纯虚函数，方便在库中使用特定点的相应功能
	  virtual void SetPassingTime(vector<Period>a, vector<Period>b, vector<Period>c, vector<Period>d) = 0;
	  virtual string GetImformation() = 0;
	  virtual void RevisePortrait(string a) = 0;
	  virtual vector<Period> GetGreen1() = 0;
	  virtual vector<Period> GetGreen2() = 0;
	  virtual vector<Period> GetGreen3() = 0;
	  virtual vector<Period> GetGreen4() = 0;
	  virtual string Getplace() = 0;
	  virtual void SetPlace(string a) = 0;
	  virtual void SetImage(IMAGE* a) = 0;
	  virtual IMAGE* GetIMAGE() = 0;
	  friend void DeleteDot(int x, int y);
	  friend void DeleteStraight(Dot* a, Dot* b);
	  friend vector<Dot*> Dijkstra(Dot* source, Dot* target, double& minDistance);
	  friend vector<Dot*> Floyd(Dot* source, Dot* target, double& minDistance);
	  friend void FindRoot_DFS(Dot* current, Dot* target, double maxLen, vector<Dot*>& path, vector<vector<Dot*>>& paths, vector<double>& pathLengths, double& currentPathLen);
	  friend bool BFS(Dot* source, Dot*& nearestStation, vector<Dot*>& path, double& minDistance, map<Dot*, double>& distances);
	  friend Dot* GetNearestStation(Dot* source, vector<Dot*>& path, double& length);
};

class Ray {     //射线，用于邻接表的存储
private:Dot* dot;
	   double length;
public:Ray(Dot* a, double b) :dot(a), length(b) {};
	  int GetDotID() { return dot->GetID(); }
	  double Getlength() { return length; }
	  friend vector<Dot*> Dijkstra(Dot* source, Dot* target, double& minDistance);
	  friend vector<Dot*> Floyd(Dot* source, Dot* target, double& minDistance);
	  friend void FindRoot_DFS(Dot* current, Dot* target, double maxLen, vector<Dot*>& path, vector<vector<Dot*>>& paths, vector<double>& pathLengths, double& currentPathLen);
	  friend bool BFS(Dot* source, Dot*& nearestStation, vector<Dot*>& path, double& minDistance, map<Dot*, double>& distances);
	  friend Dot* GetNearestStation(Dot* source, vector<Dot*>& path, double& length);
};


class OrdinaryDot :public Dot {     //普通点
private: string Getname() { return "Error"; }  //纯虚函数替代项，并无实际意义
	   void SetPassingTime(vector<Period>a, vector<Period>b, vector<Period>c, vector<Period>d) {}
	   virtual string GetImformation() { return "Error"; };
	   void RevisePortrait(string a) {};
	   virtual vector<Period> GetGreen1() { vector<Period>sb; return sb; }
	   virtual vector<Period> GetGreen2() { vector<Period>sb; return sb; }
	   virtual vector<Period> GetGreen3() { vector<Period>sb; return sb; }
	   virtual vector<Period> GetGreen4() { vector<Period>sb; return sb; }
	   virtual string Getplace() { return "Error"; }
	   virtual void SetPlace(string a) {};
	   virtual void SetImage(IMAGE* a) {};
	   virtual IMAGE* GetIMAGE() { IMAGE* sb = NULL; return sb; }
public:OrdinaryDot(int a, double b, double c) :Dot(a, b, c) {
	type = 1;
};
};


class Scenery :public Dot {         //景点
private://string portrait;   //对景点的描述，介绍
	   //string name;       //景点昵称
	  // string place;      //景点地点
	   //IMAGE* image;     //景点图片
	   void SetPassingTime(vector<Period>a, vector<Period>b, vector<Period>c, vector<Period>d) {}   //纯虚函数替代项，并无实际意义
	   virtual vector<Period> GetGreen1() { vector<Period>sb; return sb; }
	   virtual vector<Period> GetGreen2() { vector<Period>sb; return sb; }
	   virtual vector<Period> GetGreen3() { vector<Period>sb; return sb; }
	   virtual vector<Period> GetGreen4() { vector<Period>sb; return sb; }
public:Scenery(int a, double b, double c, string d) :Dot(a, b, c) {
	name = d;
	type = 2;
	portrait = "Not available";
	for (int i = 0; i < DotKu.size(); i++) {
		if (DotKu[i]->GetID() == this->GetID()) {
			DotKu[i] = this;
			SceneryKu[name] = DotKu[i];
			break;
		}
	}
}
	  Scenery() :Dot(-1, -1, -1) {
		  type = 2;
		  portrait = "Error";
	  };
	  string GetImformation() {
		  return portrait;           //获取景点信息
	  }
	  string Getname() {
		  return name;
	  }
	  string Getplace() {
		  return place;
	  }
	  IMAGE* GetIMAGE() {
		  return image;
	  }
	  void RevisePortrait(string a) {
		  portrait = a;
	  }
	  void SetPlace(string a) {       //创建地点
		  place = a;
	  }
	  void SetImage(IMAGE* a) {       //创建图片
		  image = a;
	  }
	  friend void Set_portrait(Scenery& s, string p);
	  friend vector<Dot*> InquireScenery(string t);
	  friend bool operator >(Scenery a, Scenery b);
	  friend bool operator <(Scenery a, Scenery b);
	  friend bool operator ==(Scenery a, Scenery b);
	  friend bool operator >=(Scenery a, Scenery b);
	  friend bool operator <=(Scenery a, Scenery b);
	  friend void Set_portrait(Dot* s, string p);
};


class Crossroad :public Dot {             //十字路口
private://vector<Period>Green1;          //四个路口绿灯时段，以北或者东北为第一象限，逆时针旋转90度分别得2、3、4象限
	   //vector<Period>Green2;
	   //vector<Period>Green3;
	   //vector<Period>Green4;
	   string Getname() { return "Error"; };  //纯虚函数替代项，并无实际意义
	   void RevisePortrait(string a) {}
	   void Change_portrait(string p) {}
	   virtual string GetImformation() { return "Error"; }
	   virtual string Getplace() { return "Error"; }
	   virtual void SetPlace(string a) {}
	   virtual void SetImage(IMAGE* a) {}
	   virtual IMAGE* GetIMAGE() { IMAGE* sb = NULL; return sb; }
public:Crossroad(int a, double b, double c) :Dot(a, b, c) {
	Time* Start = new Time(5, 30, 0);
	Time* GreenDuration = new Time(0, 0, 15);
	SetCrossroadPassingTime(*this, *Start,*GreenDuration);
	type = 3;
}
	  void SetPassingTime(vector<Period>a, vector<Period>b, vector<Period>c, vector<Period>d) {
		  Green1 = a;
		  Green2 = b;
		  Green3 = c;
		  Green4 = d;
	  }
	  vector<Period> GetGreen1() { return Green1; }
	  vector<Period> GetGreen2() { return Green2; }
	  vector<Period> GetGreen3() { return Green3; }
	  vector<Period> GetGreen4() { return Green4; }
};
//备注：景点路径查询，路径长度大于最短路径*1.5的路径应当舍去，且不能出现走回头路的情况

class BusStation :public Dot {     //公交站点
private:
	string Getname() { return "Error"; };  //纯虚函数替代项，并无实际意义
	void RevisePortrait(string a) {}
	void Change_portrait(string p) {}
	virtual string GetImformation() { return "Error"; }
	virtual string Getplace() { return "Error"; }
	virtual void SetPlace(string a) {}
	virtual void SetImage(IMAGE* a) {}
	virtual IMAGE* GetIMAGE() { IMAGE* sb = NULL; return sb; }
	void SetPassingTime(vector<Period>a, vector<Period>b, vector<Period>c, vector<Period>d) {}
	virtual vector<Period> GetGreen1() { vector<Period>sb; return sb; }
	virtual vector<Period> GetGreen2() { vector<Period>sb; return sb; }
	virtual vector<Period> GetGreen3() { vector<Period>sb; return sb; }
	virtual vector<Period> GetGreen4() { vector<Period>sb; return sb; }
public:BusStation(int a, double b, double c) :Dot(a, b, c) {
	type = 4;
}
};

class Line {              //线类
protected:Dot* Edge1;      //线的端点1
		 Dot* Edge2;       //线的端点2
		 double length;
		 string name;
		 int type;
public:Line(Dot* a, Dot* b, string c) :Edge1(a), Edge2(b), name(c), length(0), type(0) {          //线的构造
	LineKu.push_back(this);
};
	  virtual int GetEdge1ID() { return Edge1->GetID(); }    //虚函数实现动态绑定
	  virtual int GetEdge2ID() { return Edge2->GetID(); }
	  virtual double Getlength() { return length; }
	  virtual string Getname() { return name; }
	  virtual int Gettype() { return type; }
	  virtual double GetSlope() { return -1; }
	  friend void DeleteStraight(Dot* a, Dot* b);
	  friend void DrawStraight(Straight a, IMAGE color);
	  friend void DrawStraight(Line* a, IMAGE color);
};

class Straight :public Line {          //直线
private:double slope;         //y=kx+b中的参数
	   double intercept;
public:Straight(Dot* a, Dot* b, string c);
	  double GetSlope() { return slope; }
	  friend void DrawStraight(Straight a, IMAGE color);
};

class Curve :public Line {               //曲线,关于曲线功能扩展在完成基本功能后来实现
private:function<double(double)> formula;       //曲线的函数解析式（相当于y=f(x))
public:Curve(Dot* a, Dot* b, string c, string form);     //第四个参数表述用户输入曲线的函数解析式，用程序的解析器将其解析为函数作为曲线的成员数据
	  friend void DrawCurve(Curve a, IMAGE color);
};

//查找路径的函数定义
// 通过自己创建的数据结构写Dijkstra算法，返回最短路径，并通过引用参数返回最短路径距离
vector<Dot*> Dijkstra(Dot* source, Dot* target, double& minDistance);
// 通过自己创建的数据结构写Floyd算法，返回最短路径，并通过引用参数返回最短路径距离
vector<Dot*> Floyd(Dot* source, Dot* target, double& minDistance);
// 深度优先搜索（DFS）实现路径的查找
void FindRoot_DFS(Dot* current, Dot* target, double maxLen, vector<Dot*>& path, vector<vector<Dot*>>& paths, vector<double>& pathLengths, double& currentPathLen);
// 查找所有满足条件的路径，并通过引用参数返回每条路径对应的最短路径距离，返回的最短路径以及距离根据路径长度进行排序
vector<vector<Dot*>> FindRoot(Dot* source, Dot* target, vector<double>& pathLengths);



OrdinaryDot* CreateOrdinaryDot(double x, double y);//选择地图上相应的点，根据坐标构建普通点（仅限管理员功能）
Scenery* CreateScenery(double x, double y, string name);//输入景点名字，选择地图上相应的点，根据坐标构建景点（仅限管理员功能）
Crossroad* CreateCrossroad(double x, double y);//选择地图上相应的点，根据坐标构建十字路口（仅限管理员功能）
Straight* CreateStraight(Dot* a, Dot* b, string name);//根据直线的两个端点并输入道路的名字，创建直线(做界面的时候可能还需要加入界面处理的一些操作）（仅限管理员功能）
void Set_portrait(Scenery& s, string p);//创建或修改景点的描述（仅限管理员功能）
void DeleteDot(int x, int y);//传入待删除点的坐标，删除此点(做界面的时候可能还需要加入界面处理的一些操作）（仅限管理员功能）
void DeleteStraight(Dot* a, Dot* b); //传入待删除直线所连接的两个点，删除对应的直线(做界面的时候可能还需要加入界面处理的一些操作）（仅限管理员功能）
void DeleteStraight(string name); //重载函数：传入道路的名字，删除对应的直线（仅限管理员功能）

//地图绘制
void Download();
void DrawStraight(Straight a, IMAGE color);
void DrawCurve(Curve a, IMAGE color);
void DrawStraight(Line* a, IMAGE color);
void DrawMap();
void DrawPath(vector<Dot*>Path, IMAGE color);
void DrawPath(vector<Dot*>Path, bool isshort);
void DrawRoots(Dot* source, Dot* target);
void DrawSchoolBusRoot(SchoolBus a);

//导航功能
Time GetSystemTime();
void CalculateRootTime(vector<Dot*> path, Time& ArriveTime, Time& ProcessTime, double speed, int& CrossroadSum);
bool BusNavigation(Dot* source, Dot* target, double& walkinglength1, double& Buslength, double& walkinglength2, vector<Dot*>& path1, vector<Dot*>& path2, vector<Dot*>& path3);

//保存功能
void SaveProgram(string outfile1, string outfile2, string outfile3, string outfile4, string outfile5, string outfile6, string outfile7);
void ReadProgram(string infile1, string infile2, string infile3, string infile4, string infile5, string infile6, string infile7);
void SaveProgram(string outfile1, string outfile2);
void ReadProgram(string infile1, string infile2);

//查询景点
vector<Dot*> InquireScenery(string t);

void Set_portrait(Dot* s, string p);